package dryven.sapi.servlet_v25;

import java.io.IOException;
import java.io.InputStream;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import dryven.config.ApplicationConfiguration;
import dryven.config.xml.XMLConfigFileParser;
import dryven.init.DefaultFrontControllerFactory;
import dryven.init.FrontControllerFactory;
import dryven.request.ExceptionFrontController;
import dryven.request.FrontController;
import dryven.request.http.Request;
import dryven.request.http.Response;

public class DryvenServlet extends HttpServlet {

	/**
	 * 
	 */
	private static final long serialVersionUID = 913306797978635663L;
	private static final String DRYVEN_ATTRIBUTE = "dryven-frontcontroller-attr";
	
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		Request dryvenRequest = createRequest(req);
		Response dryvenResponse = createResponse(resp);
		FrontController frontController = getFrontController();
		frontController.handleRequest(dryvenRequest, dryvenResponse);
	}

	protected Response createResponse(HttpServletResponse resp) {
		Response dryvenResponse = new ServletResponse(resp);
		return dryvenResponse;
	}

	protected Request createRequest(HttpServletRequest req) {
		Request dryvenRequest = new ServletRequest(req);
		return dryvenRequest;
	}

	@Override
	public void init(ServletConfig config) throws ServletException {
		super.init(config);
	}
	
	
	
	public FrontController getFrontController() {
		Object oFrontCtrl = getServletContext().getAttribute(DRYVEN_ATTRIBUTE);
		if(oFrontCtrl==null) {
			FrontController frontCtrl = null;
			try {
				ApplicationConfiguration cfg = createConfiguration();
				FrontControllerFactory factory = null;
				try {
					factory = cfg.getFrontControllerFactoryClass().newInstance();
				} catch (Exception e) {
					throw new RuntimeException(String.format("Could not instanciate application delegate %s",cfg.getFrontControllerFactoryClass().getName(), e));
				}
				frontCtrl = factory.createFrontController(cfg);
			} catch(Exception e) {
				frontCtrl = new ExceptionFrontController(e);
			}
			oFrontCtrl = frontCtrl;
			getServletContext().setAttribute(DRYVEN_ATTRIBUTE, oFrontCtrl);
		}
		return (FrontController)oFrontCtrl;
	}
	
	protected ApplicationConfiguration createConfiguration() {
		InputStream doc = getServletContext().getResourceAsStream("/config/app.xml");
		XMLConfigFileParser parser = new XMLConfigFileParser(doc);
		return new ServletApplicationConfiguration(getServletContext(),parser.parse());
	}

	@Override
	public void destroy() {
		FrontController fCtrl = (FrontController) getServletContext().getAttribute(DRYVEN_ATTRIBUTE);
		if(fCtrl!=null) {
			fCtrl.shutdown();
		}
		getServletContext().removeAttribute(DRYVEN_ATTRIBUTE);
		super.destroy();
	}

}
